package com.mtsmda.collection;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;

public class SetDemo {

	public static void main(String[] args) {
		hashSetDemo();
		System.out.println("\n ----- \n");
		treeSetDemo();
		System.out.println("\n ----- \n");
		linkedHashSetDemo();
	}

	/**
	 * <p>
	 * This class implements the Set interface, backed by a hash table (actually
	 * a HashMap instance). It makes no guarantees as to the iteration order of
	 * the set; in particular, it does not guarantee that the order will remain
	 * constant over time. This class permits the null element. This class
	 * offers constant time performance for the basic operations (add, remove,
	 * contains and size), assuming the hash function disperses the elements
	 * properly among the buckets. Iterating over this set requires time
	 * proportional to the sum of the HashSet instance's size (the number of
	 * elements) plus the "capacity" of the backing HashMap instance (the number
	 * of buckets). Thus, it's very important not to set the initial capacity
	 * too high (or the load factor too low) if iteration performance is
	 * important.
	 * </p>
	 * 
	 * <hr/>
	 * <p>
	 * HashSet, which stores its elements in a hash table, is the
	 * best-performing implementation; however it makes no guarantees concerning
	 * the order of iteration.
	 * </p>
	 * */
	private static void hashSetDemo() {
		Set<String> hashSet = new HashSet<>();
		System.out.println(hashSet.add(new String("Barcelona")));
		System.out.println(hashSet.add(new String("Barcelona")));
		System.out.println(hashSet.add(null));
		System.out.println(hashSet.add(new String("Spartak")));
		System.out.println(hashSet.add(new String("barcelona")));
		System.out.println(hashSet.add(new String("Milan")));
		System.out.println(hashSet.add(new String("Chelsea")));
		System.out.println(hashSet.add(null));
		System.out.println(hashSet.size());
		for (String s : hashSet) {
			if (s == null) {
				continue;
			}
			System.out.println(s + "  " + s.hashCode());
		}
	}

	/**
	 * <p>
	 * A NavigableSet implementation based on a TreeMap. The elements are
	 * ordered using their natural ordering, or by a Comparator provided at set
	 * creation time, depending on which constructor is used. This
	 * implementation provides guaranteed log(n) time cost for the basic
	 * operations (add, remove and contains).
	 * 
	 * Note that the ordering maintained by a set (whether or not an explicit
	 * comparator is provided) must be consistent with equals if it is to
	 * correctly implement the Set interface. (See Comparable or Comparator for
	 * a precise definition of consistent with equals.) This is so because the
	 * Set interface is defined in terms of the equals operation, but a TreeSet
	 * instance performs all element comparisons using its compareTo (or
	 * compare) method, so two elements that are deemed equal by this method
	 * are, from the standpoint of the set, equal. The behavior of a set is
	 * well-defined even if its ordering is inconsistent with equals; it just
	 * fails to obey the general contract of the Set interface.
	 * 
	 * <hr/>
	 * <p>
	 * TreeSet, which stores its elements in a red-black tree, orders its
	 * elements based on their values; it is substantially slower than HashSet.
	 * </p>
	 * */
	private static void treeSetDemo() {
		Set<String> treeSet = new TreeSet<>();
		System.out.println(treeSet.add(new String("Moldova")));
		// System.out.println(treeSet.add(null));
		System.out.println(treeSet.add(new String("moldova")));
		System.out.println(treeSet.add(new String("Moldova")));
		System.out.println(treeSet.add(new String("Russia")));
		System.out.println(treeSet.add(new String("USA")));
		System.out.println(treeSet.add(new String("Brasil")));
		System.out.println(treeSet.contains(new String("")));
		System.out.println(treeSet.contains(new String("Russia")));
		System.out.println(treeSet.size());
		for (String s : treeSet) {
			System.out.println(s + "  " + s.hashCode());
		}
		System.out.println(treeSet.hashCode());

	}

	/**
	 * <p>
	 * Hash table and linked list implementation of the Set interface, with
	 * predictable iteration order. This implementation differs from HashSet in
	 * that it maintains a doubly-linked list running through all of its
	 * entries. This linked list defines the iteration ordering, which is the
	 * order in which elements were inserted into the set (insertion-order).
	 * Note that insertion order is not affected if an element is re-inserted
	 * into the set. (An element e is reinserted into a set s if s.add(e) is
	 * invoked when s.contains(e) would return true immediately prior to the
	 * invocation.)
	 * 
	 * <hr/>
	 * <p>
	 * LinkedHashSet, which is implemented as a hash table with a linked list
	 * running through it, orders its elements based on the order in which they
	 * were inserted into the set (insertion-order). LinkedHashSet spares its
	 * clients from the unspecified, generally chaotic ordering provided by
	 * HashSet at a cost that is only slightly higher.
	 * </p>
	 * */
	private static void linkedHashSetDemo() {
		Set<String> linkedHashSet = new LinkedHashSet<>();
		System.out.println(linkedHashSet.add(new String("Moldova")));
		System.out.println(linkedHashSet.add(null));
		System.out.println(linkedHashSet.add(new String("moldova")));
		System.out.println(linkedHashSet.add(new String("Moldova")));
		System.out.println(linkedHashSet.add(new String("Russia")));
		System.out.println(linkedHashSet.add(new String("USA")));
		System.out.println(linkedHashSet.add(new String("Brasil")));
		System.out.println(linkedHashSet.contains(new String("")));
		System.out.println(linkedHashSet.contains(new String("Russia")));
		System.out.println(linkedHashSet.size());
		for (String s : linkedHashSet) {
			if(s == null){
				continue;
			}
			System.out.println(s + "  " + s.hashCode());
		}
		System.out.println(linkedHashSet.hashCode());

	}
	// <p></p>

}